package tgeo;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.MalformedInputException;
import java.util.Map;

import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;
import org.xml.sax.SAXException;

public class SchemaValidationView extends ViewPart {
	public static final String ID = "tgeo.views.SchemaValidationView";
	
	SashForm sash = null;
	Composite leftCtrl = null;
	Composite rightCtrl = null;
	Button btnValidation = null;
	Text txtResult = null;
	Text txtXSDFile = null;
	Button btnLoadXSD = null;
	Text txtXMLFile = null;
	Button btnLoadXML = null;
	StyledText txtXSD = null;
	StyledText txtXML = null;
	Label lblEncoding = null;
	Combo cboEncoding = null;
	
	String encoding = null;
	final int PAD = 10;
	
	
	public SchemaValidationView() {
		
	}

	@Override
	public void createPartControl(Composite parent) {
		parent.setBackgroundMode(SWT.INHERIT_DEFAULT);
		Layout layout = new FormLayout();
		FormData data = null;
		
		btnValidation = new Button(parent, SWT.PUSH);
		txtResult = new Text(parent, SWT.BORDER);
		sash = new SashForm(parent, SWT.HORIZONTAL);
		Composite leftCtrl = new Composite(sash, SWT.BORDER);
		Composite rightCtrl = new Composite(sash, SWT.BORDER);

		parent.setLayout(layout);
		leftCtrl.setLayout(parent.getLayout());
		rightCtrl.setLayout(parent.getLayout());
		
		btnLoadXSD = new Button(leftCtrl, SWT.PUSH);
		btnLoadXML = new Button(rightCtrl, SWT.PUSH);
		txtXSDFile = new Text(leftCtrl, SWT.BORDER|SWT.READ_ONLY);
		txtXMLFile = new Text(rightCtrl, SWT.BORDER|SWT.READ_ONLY);
		txtXSD = new StyledText(leftCtrl, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
		txtXML = new StyledText(rightCtrl, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
		lblEncoding = new Label(parent, SWT.NONE);
		cboEncoding = new Combo(parent, SWT.BORDER);
		
		sash.setWeights(new int []{50, 50});
		btnValidation.setText("Validation");
		btnLoadXSD.setText("Open xsd");
		btnLoadXML.setText("Open xml");
		lblEncoding.setText("Charset");
        Map<String, Charset> mapCharset = Charset.availableCharsets();
	    for(String k : mapCharset.keySet()){
	    	Charset charset = mapCharset.get(k);
	    	cboEncoding.add(charset.toString());
	    }
	    cboEncoding.setText(Charset.defaultCharset().toString());
		
		data = new FormData();
		data.top = new FormAttachment(0, PAD);
		data.left = new FormAttachment(0, PAD);
		lblEncoding.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(0, PAD);
		data.left = new FormAttachment(lblEncoding, PAD);
		cboEncoding.setLayoutData(data);
		
		data = new FormData(100, 50);
		data.bottom = new FormAttachment(100, -PAD);
		data.left = new FormAttachment(0, PAD);
		btnValidation.setLayoutData(data);

		data = new FormData();
		data.bottom = new FormAttachment(100, -PAD);
		data.left = new FormAttachment(btnValidation, PAD);
		data.right = new FormAttachment(100, -PAD);
		data.height = 50;
		txtResult.setLayoutData(data);
		
		data = new FormData();
		data.top = new FormAttachment(cboEncoding, PAD);
		data.left = new FormAttachment(0, PAD);
		data.right = new FormAttachment(100, -PAD);
		data.bottom = new FormAttachment(txtResult, -PAD);
		sash.setLayoutData(data);

		// left
		data = new FormData(100, 25);
		data.top = new FormAttachment(0, PAD);
		data.right = new FormAttachment(100, -PAD);
		btnLoadXSD.setLayoutData(data);

		data = new FormData(100, 17);
		data.top = new FormAttachment(0, PAD);
		data.left = new FormAttachment(0, PAD);
		data.right = new FormAttachment(btnLoadXSD, -PAD);
		txtXSDFile.setLayoutData(data);
		
		data = new FormData();
		data.top = new FormAttachment(txtXSDFile, PAD);
		data.left = new FormAttachment(0, PAD);
		data.right = new FormAttachment(100, -PAD);
		data.bottom = new FormAttachment(100, -PAD);
		txtXSD.setLayoutData(data);

		// right
		data = new FormData(100, 25);
		data.top = new FormAttachment(0, PAD);
		data.right = new FormAttachment(100, -PAD);
		btnLoadXML.setLayoutData(data);
		
		data = new FormData(100, 17);
		data.top = new FormAttachment(0, PAD);
		data.left = new FormAttachment(0, PAD);
		data.right = new FormAttachment(btnLoadXML, -PAD);
		txtXMLFile.setLayoutData(data);

		data = new FormData();
		data.top = new FormAttachment(txtXMLFile, PAD);
		data.left = new FormAttachment(0, PAD);
		data.right = new FormAttachment(100, -PAD);
		data.bottom = new FormAttachment(100, -PAD);
		txtXML.setLayoutData(data);
	
		addListener(parent);
	}
	
	private void addListener(final Composite parent){
		this.btnValidation.addSelectionListener(new SelectionListener(){
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
			@Override
			public void widgetSelected(SelectionEvent e) {
				String xsdString = txtXSD.getText();
				String xmlString = txtXML.getText();
				String retString = validationCheck(xmlString, xsdString);
				if(retString.isEmpty())
					retString = "OK";
				txtResult.setText(retString);
			}
		});
		
		this.btnLoadXSD.addSelectionListener(new SelectionListener(){
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
			@Override
			public void widgetSelected(SelectionEvent e) {
				FileDialog dlg = new FileDialog(parent.getShell(), SWT.OPEN);
				dlg.setFilterExtensions(new String []{"*.xsd"});
				String path = dlg.open();
				if(path == null)
					return;
				txtXSDFile.setText(path);
				try {
					FileInputStream xmlFile = new FileInputStream(path);
			        FileChannel channel = xmlFile.getChannel();   
			        ByteBuffer byteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());   
			        String charsetName = cboEncoding.getText();
			        Charset charset = Charset.forName(charsetName);
			        System.out.println(charset.toString());  
			        try{
				        CharsetDecoder decoder = charset.newDecoder();   
				        CharBuffer charBuffer = decoder.decode(byteBuffer);   
						txtXSD.setText(charBuffer.toString());
			        }catch(MalformedInputException e3){
			        	
			        }
			        channel.close();   
				} catch (FileNotFoundException e1) {
					e1.printStackTrace();
				} catch (IOException e2) {
					e2.printStackTrace();
				}				
			}
		});
		this.btnLoadXML.addSelectionListener(new SelectionListener(){
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
			@Override
			public void widgetSelected(SelectionEvent e) {
				FileDialog dlg = new FileDialog(parent.getShell(), SWT.OPEN);
				dlg.setFilterExtensions(new String []{"*.xml"});
				String path = dlg.open();
				if(path == null)
					return;
				txtXMLFile.setText(path);
				try {
					FileInputStream xmlFile = new FileInputStream(path);
			        FileChannel channel = xmlFile.getChannel();   
			        ByteBuffer byteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());   
//			        Charset charset = Charset.defaultCharset();
			        String charsetName = cboEncoding.getText();
			        Charset charset = Charset.forName(charsetName);
			        System.out.println(charset.toString());
					try {
						CharsetDecoder decoder = charset.newDecoder();
						CharBuffer charBuffer = decoder.decode(byteBuffer);
						txtXML.setText(charBuffer.toString());
					} catch (MalformedInputException e3) {

					}
					channel.close();
				} catch (FileNotFoundException e1) {
					e1.printStackTrace();
				} catch (IOException e2) {
					e2.printStackTrace();
				}
			}
		});

	}

	@Override
	public void setFocus() {
	}
	
    /**
     * XML 스키마 체크에 대한 결과를 리턴한다.
     * @param xmlString
     * @param xsdString
     * @return 성공시 "", 실패시 에러메시지 리턴
     */
    public static String validationCheck(String xmlString, String xsdString){
        String schemaLang = "http://www.w3.org/2001/XMLSchema";
        SchemaFactory factory = SchemaFactory.newInstance(schemaLang);
        Schema schema=null;
    	try {
    		schema = factory.newSchema(new StreamSource(new StringReader(xsdString)));
    	} catch (SAXException e) {
    		e.printStackTrace();
    	}
        Validator validator = schema.newValidator();
        try {
    		validator.validate(new StreamSource(new StringReader(xmlString)));
        } catch (SAXException e) {
    		return e.getMessage();
    	} catch (IOException e) {
    		return e.getMessage();
    	} 
		return "";
    }   
}
